package com.alex.controller.Topic_Idea_Assistant;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.alex.common.config.IndexConfig;
import com.alex.controller.Cn_Pubmed.AuthNetWork;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;

import java.io.Serializable;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

public class GeneNetWork {


    public static ResultVoEntity avg(List<Integer> pmOrUtIdList) throws SQLException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(new Date()) + " 程序开始了~~~");
        long t0 = System.currentTimeMillis();
        String limit = "";
        int onePageNum = 1000;
        String pmUtAidInfoTable = IndexConfig.db_article;
        System.out.println("pmOrUtIdList.size(): " + pmOrUtIdList.size());
        /**
         * getNetWorkInfo为主方法，参数，pmOrUtIdList：表pm_ut_aid_info自增主键的集合，即ES检索的结果。pmUtAidInfoTable：表名。
         */
        AuthNetWork.NetWorkInfo netWorkInfo = getNetWorkInfo(pmOrUtIdList, pmUtAidInfoTable);
        List<AuthNetWork.Category> categories = netWorkInfo.getCategories();
        Set<AuthNetWork.Link> links = netWorkInfo.getLinks();
        Set<AuthNetWork.Nodes> nodes = netWorkInfo.getNodes();

        Set<AuthNetWork.Nodes> collect = new HashSet<>(nodes.stream()
                .collect(Collectors.toMap(AuthNetWork.Nodes::getName, node -> node, (node1, node2) -> node1))
                .values());

        for (AuthNetWork.Nodes nodesOne : collect) {
            nodesOne.setValue("" + nodesOne.getSymbolSize());
        }

        return new ResultVoEntity(categories, links, collect);

    }


    private static AuthNetWork.NetWorkInfo getNetWorkInfo(List<Integer> pmOrUtIdList, String pmUtAidInfoTable) throws SQLException {
        if (null == pmOrUtIdList || pmOrUtIdList.isEmpty()) {
            return new AuthNetWork.NetWorkInfo();
        }
        System.out.println("读的表是:"+pmUtAidInfoTable);
        List<Entity> tableData = Db.use().query("select `aid`,`drug_gene_pathway_disease` from " + pmUtAidInfoTable + " where aid in(" + CollUtil.join(new HashSet<>(pmOrUtIdList), ",") + ");");
        Map<String, Integer> wordAndWordIdMap = new HashMap<>();
        Map<Integer, String> wordIdAndWordMap = new HashMap<>();
        Map<Integer, Set<Integer>> wordIdAndAidSetMap = new HashMap<>();
        List<AuthNetWork.Category> categoriesList = new ArrayList<>();
        Set<AuthNetWork.Nodes> nodesSet = new HashSet<>();
        Set<AuthNetWork.Link> linkSet = new HashSet<>();
        Map<Integer, Set<Integer>> codeAndWordIdSetMap = new HashMap<>();
        for (Entity entry : tableData) {
            Integer aid = entry.getInt("aid");
            String categoryAndInfos = entry.getStr("drug_gene_pathway_disease");
            if (null != aid && aid > 0 && null != categoryAndInfos && categoryAndInfos.length() > 4) {
                try {
                    List<CategoryAndInfo> categoryAndInfoList = JSONObject.parseArray(categoryAndInfos, CategoryAndInfo.class);
                    Set<Integer> wordIdSet = new HashSet<>();
                    for (CategoryAndInfo categoryAndInfo : categoryAndInfoList) {
                        List<CodeAndWordList> infoList = categoryAndInfo.getInfoList();
                        for (CodeAndWordList codeAndWordList : infoList) {
                            int code = codeAndWordList.getCode();
                            List<String> wordList = codeAndWordList.getWordList();
                            for (String word : wordList) {
                                if (null != word && word.length() > 1) {
                                    word = word.toLowerCase().trim();
                                    int wordId;
                                    if (wordAndWordIdMap.containsKey(word)) {
                                        wordId = wordAndWordIdMap.get(word);
                                    } else {
                                        wordId = wordAndWordIdMap.size() + 1;
                                        wordIdAndWordMap.put(wordId, word);
                                        wordAndWordIdMap.put(word, wordId);
                                    }
                                    wordIdSet.add(wordId);
                                    putIntSetIntMap(wordIdAndAidSetMap, wordId, aid);
                                    putIntSetStr(code, wordId, codeAndWordIdSetMap);
                                }
                            }
                        }
                    }
                    addLinkSet(new ArrayList<>(wordIdSet), linkSet);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        for (Map.Entry<Integer, Set<Integer>> entry : codeAndWordIdSetMap.entrySet()) {
            Integer key = entry.getKey();
            // code为数字代号，药物，数字代号：1；基因，数字代号：2；通路，数字代号：3；疾病，数字代号：4。
//            String name = "药物";
//            name = (key == 2) ? "基因" : name;
//            name = (key == 3) ? "通路" : name;
//            name = (key == 4) ? "疾病" : name;
            String name = "药物";
            name = (key == 2) ? "基因" : name;
            name = (key == 3) ? "通路" : name;
            name = (key == 4) ? "疾病" : name;
            AuthNetWork.Category category = new AuthNetWork.Category();
            category.setName(name);
            categoriesList.add(category);
            Set<Integer> wordIdSet = entry.getValue();
            for (Integer wordId : wordIdSet) {
                if (wordIdAndWordMap.containsKey(wordId)) {
                    String word = wordIdAndWordMap.get(wordId);
                    AuthNetWork.Nodes nodes = new AuthNetWork.Nodes();
                    nodes.setCategory(name);
                    nodes.setId(wordId);
                    if (wordIdAndAidSetMap.containsKey(wordId)) {
                        Set<Integer> aidSet = wordIdAndAidSetMap.get(wordId);
                        nodes.setSymbolSize(aidSet.size());
                        nodes.setAidList(new ArrayList<>(aidSet));
                    }
                    nodes.setName(word);
                    nodesSet.add(nodes);
                }
            }
        }

        AuthNetWork.NetWorkInfo netWorkInfo = new AuthNetWork.NetWorkInfo();
        netWorkInfo.setCategories(categoriesList);
        netWorkInfo.setLinks(linkSet);
        netWorkInfo.setNodes(nodesSet);
        return netWorkInfo;
    }

    public static void putIntSetIntMap(Map<Integer, Set<Integer>> authIdAndAidSetMap, int authId, int aid) {
        authIdAndAidSetMap.compute(authId, (k, v) -> {
            if (v == null) {
                v = new ConcurrentHashSet<>();
            }
            v.add(aid);
            return v;
        });
    }

    // 两个id之间的连线，这里采用第一个id必须大于第二个id，以避免重复连线。
    public static void addLinkSet(List<Integer> authIdList, Set<AuthNetWork.Link> linkSet) {
        if (authIdList.size() > 1) {
            for (int i = 0; i < authIdList.size(); i++) {
                int a = authIdList.get(i);
                for (int j = i + 1; j < authIdList.size(); j++) {
                    int b = authIdList.get(j);
                    if (a != b) {
                        AuthNetWork.Link link = new AuthNetWork.Link();
                        if (a > b) {
                            link.setSource(a);
                            link.setTarget(b);
                        } else {
                            link.setSource(b);
                            link.setTarget(a);
                        }
                        linkSet.add(link);
                    }
                }
            }
        }
    }



    public static void putIntSetStr(Integer code, Integer wordId, Map<Integer, Set<Integer>> codeAndWordIdSetMap) {
        if (code > 0 && wordId > 0) {
            codeAndWordIdSetMap.compute(code, (k, v) -> {
                if (v == null) {
                    v = new ConcurrentHashSet<>();
                }
                v.add(wordId);
                return v;
            });
        }
    }

    // 实体类，用于存储指定类别的数字代号和关键词集合。category类别共分为三种：标题ti为7、关键词ky为8、摘要ab为9。
    @Data
    public static class CategoryAndInfo implements Serializable {
        private static final long serialVersionUID = 1L;
        private List<CodeAndWordList> infoList = new ArrayList<>();
        private int category = 0;
    }

    // 实体类，用于存储从标题、关键词、摘要中提取出来的疾病、药物、通路、基因等关键词。code为数字代号，药物，数字代号：1；基因，数字代号：2；通路，数字代号：3；疾病，数字代号：4。
    @Data
    public static class CodeAndWordList implements Serializable {
        private static final long serialVersionUID = 1L;
        private List<String> wordList = new ArrayList<>();
        private int code = 0;
    }


// end
}
